css: Implement text-transform
authorMatthias Clasen <mclasen@redhat.com>
Fri, 20 Aug 2021 23:01:01 +0000 (19:01 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Sun, 22 Aug 2021 19:57:50 +0000 (15:57 -0400)
Implement the text-transform property from
https://www.w3.org/TR/css-text-3/#text-transform-property
using a new Pango attribute.

docs/reference/gtk/css-properties.md
gtk/gtkcssanimatedstyle.c
gtk/gtkcssenumvalue.c
gtk/gtkcssenumvalueprivate.h
gtk/gtkcssstaticstyle.c
gtk/gtkcssstyle.c
gtk/gtkcssstyleprivate.h
gtk/gtkcssstylepropertyimpl.c
gtk/gtkcsstypesprivate.h

index c6818184a49ace733f8d4f242745a0b4d1425136..5b3587e75a6ec07ef8f07e589b7fc740ac4f432c 100644 (file)
@@ -162,6 +162,7 @@ done with
 |caret-color|[CSS Basic User Interface Level 3](https://www.w3.org/TR/css3-ui/#caret-color) | CSS allows an auto value |
 |-gtk-secondary-caret-color|[Color](https://www.w3.org/TR/css-color-3/#valuea-def-color) | used for the secondary caret in bidirectional text |
 |letter-spacing| [CSS Text Level 3](https://www.w3.org/TR/css3-text/#letter-spacing) | |
+|text-transform| [CSS Text Level 3](https://www.w3.org/TR/css-text-3/#text-transform-property) | CSS allows full-width and full-size-kana. Since 4.6 |
 |line-height| [CSS Inline Layout Level 3](https://www.w3.org/TR/css-inline-3/#line-height-property) | Since 4.6 |
 |text-decoration-line| [CSS Text Decoration Level 3](https://www.w3.org/TR/css-text-decor-3/#text-decoration-line-property) | |
 |text-decoration-color| [CSS Text Decoration Level 3](https://www.w3.org/TR/css-text-decor-3/#text-decoration-color-property) | |
index eb62780360a755e47c602d217a09a214c856a782..fdfcf17f1fc5b51e37e41bfdfebc176905260eda 100644 (file)
@@ -220,6 +220,10 @@ gtk_css_animated_style_set_animated_value (GtkCssAnimatedStyle *animated,
       unshare_font_variant (animated);
       gtk_css_take_value (&style->font_variant->text_decoration_style, value);
       break;
+    case GTK_CSS_PROPERTY_TEXT_TRANSFORM:
+      unshare_font_variant (animated);
+      gtk_css_take_value (&style->font_variant->text_transform, value);
+      break;
     case GTK_CSS_PROPERTY_FONT_KERNING:
       unshare_font_variant (animated);
       gtk_css_take_value (&style->font_variant->font_kerning, value);
index ce96a23e0c982ba101a387ad40a79fe23b9dbd11..dfb7a0d394f3e0a43e36147ad93d7c10a9d8f922 100644 (file)
@@ -1568,3 +1568,55 @@ _gtk_css_font_variant_east_asian_value_get (const GtkCssValue *value)
 
   return value->value;
 }
+
+/* GtkTextTransform */
+
+static const GtkCssValueClass GTK_CSS_VALUE_TEXT_TRANSFORM = {
+  "GtkCssTextTransformValue",
+  gtk_css_value_enum_free,
+  gtk_css_value_enum_compute,
+  gtk_css_value_enum_equal,
+  gtk_css_value_enum_transition,
+  NULL,
+  NULL,
+  gtk_css_value_enum_print
+};
+
+static GtkCssValue text_transform_values[] = {
+  { &GTK_CSS_VALUE_TEXT_TRANSFORM, 1, TRUE, GTK_CSS_TEXT_TRANSFORM_NONE, "none" },
+  { &GTK_CSS_VALUE_TEXT_TRANSFORM, 1, TRUE, GTK_CSS_TEXT_TRANSFORM_LOWERCASE, "lowercase" },
+  { &GTK_CSS_VALUE_TEXT_TRANSFORM, 1, TRUE, GTK_CSS_TEXT_TRANSFORM_UPPERCASE, "uppercase" },
+  { &GTK_CSS_VALUE_TEXT_TRANSFORM, 1, TRUE, GTK_CSS_TEXT_TRANSFORM_CAPITALIZE, "capitalize" },
+};
+
+GtkCssValue *
+_gtk_css_text_transform_value_new (GtkTextTransform transform)
+{
+  g_return_val_if_fail (transform < G_N_ELEMENTS (text_transform_values), NULL);
+
+  return _gtk_css_value_ref (&text_transform_values[transform]);
+}
+
+GtkCssValue *
+_gtk_css_text_transform_value_try_parse (GtkCssParser *parser)
+{
+  guint i;
+
+  g_return_val_if_fail (parser != NULL, NULL);
+
+  for (i = 0; i < G_N_ELEMENTS (text_transform_values); i++)
+    {
+      if (gtk_css_parser_try_ident (parser, text_transform_values[i].name))
+        return _gtk_css_value_ref (&text_transform_values[i]);
+    }
+
+  return NULL;
+}
+
+GtkTextTransform
+_gtk_css_text_transform_value_get (const GtkCssValue *value)
+{
+  g_return_val_if_fail (value->class == &GTK_CSS_VALUE_TEXT_TRANSFORM, GTK_CSS_TEXT_TRANSFORM_NONE);
+
+  return value->value;
+}
index a102a8650b3fe910db8bc72badd0effb134b898e..b6d3b0f7573941388522cc717014922217d217ec 100644 (file)
@@ -115,6 +115,9 @@ GtkCssFontVariantEastAsian _gtk_css_font_variant_east_asian_try_parse_one (GtkCs
                                                                       GtkCssFontVariantEastAsian base);
 GtkCssFontVariantEastAsian _gtk_css_font_variant_east_asian_value_get     (const GtkCssValue          *value);
 
+GtkCssValue *          _gtk_css_text_transform_value_new       (GtkTextTransform transform);
+GtkCssValue *          _gtk_css_text_transform_value_try_parse (GtkCssParser           *parser);
+GtkTextTransform       _gtk_css_text_transform_value_get       (const GtkCssValue      *value);
 G_END_DECLS
 
 #endif /* __GTK_CSS_ENUM_VALUE_PRIVATE_H__ */
index ad906431d821d2e4d932e01b6761563d59e32ea9..ba7d2ff9582ca6b130e9a0b4816e3ff488c7a635 100644 (file)
@@ -118,6 +118,7 @@ static const int font_variant_props[] = {
   GTK_CSS_PROPERTY_TEXT_DECORATION_LINE,
   GTK_CSS_PROPERTY_TEXT_DECORATION_COLOR,
   GTK_CSS_PROPERTY_TEXT_DECORATION_STYLE,
+  GTK_CSS_PROPERTY_TEXT_TRANSFORM,
   GTK_CSS_PROPERTY_FONT_KERNING,
   GTK_CSS_PROPERTY_FONT_VARIANT_LIGATURES,
   GTK_CSS_PROPERTY_FONT_VARIANT_POSITION,
@@ -430,6 +431,9 @@ gtk_css_static_style_set_value (GtkCssStaticStyle *sstyle,
     case GTK_CSS_PROPERTY_TEXT_DECORATION_STYLE:
       gtk_css_take_value (&style->font_variant->text_decoration_style, value);
       break;
+    case GTK_CSS_PROPERTY_TEXT_TRANSFORM:
+      gtk_css_take_value (&style->font_variant->text_transform, value);
+      break;
     case GTK_CSS_PROPERTY_FONT_KERNING:
       gtk_css_take_value (&style->font_variant->font_kerning, value);
       break;
@@ -810,6 +814,7 @@ gtk_css_font_variant_create_initial_values (void)
   values->text_decoration_line = _gtk_css_initial_value_new_compute (GTK_CSS_PROPERTY_TEXT_DECORATION_LINE, NULL, NULL, NULL);
   values->text_decoration_color = NULL;
   values->text_decoration_style = _gtk_css_initial_value_new_compute (GTK_CSS_PROPERTY_TEXT_DECORATION_STYLE, NULL, NULL, NULL);
+  values->text_transform = _gtk_css_initial_value_new_compute (GTK_CSS_PROPERTY_TEXT_TRANSFORM, NULL, NULL, NULL);
   values->font_kerning = _gtk_css_initial_value_new_compute (GTK_CSS_PROPERTY_FONT_KERNING, NULL, NULL, NULL);
   values->font_variant_ligatures = _gtk_css_initial_value_new_compute (GTK_CSS_PROPERTY_FONT_VARIANT_LIGATURES, NULL, NULL, NULL);
   values->font_variant_position = _gtk_css_initial_value_new_compute (GTK_CSS_PROPERTY_FONT_VARIANT_POSITION, NULL, NULL, NULL);
index 92a7398988ac8312e0a189cd13d530498e701bd2..652f9a7a78f4f1266bbe357360059f7ec8502aa8 100644 (file)
@@ -126,6 +126,8 @@ gtk_css_style_get_value (GtkCssStyle *style,
       return style->font_variant->text_decoration_color ? style->font_variant->text_decoration_color : style->core->color;
     case GTK_CSS_PROPERTY_TEXT_DECORATION_STYLE:
       return style->font_variant->text_decoration_style;
+    case GTK_CSS_PROPERTY_TEXT_TRANSFORM:
+      return style->font_variant->text_transform;
     case GTK_CSS_PROPERTY_FONT_KERNING:
       return style->font_variant->font_kerning;
     case GTK_CSS_PROPERTY_FONT_VARIANT_LIGATURES:
@@ -400,6 +402,24 @@ get_pango_underline_from_style (GtkTextDecorationStyle style)
   g_return_val_if_reached (PANGO_UNDERLINE_SINGLE);
 }
 
+static PangoTextTransform
+get_pango_text_transform_from_style (GtkTextTransform transform)
+{
+  switch (transform)
+    {
+    case GTK_CSS_TEXT_TRANSFORM_NONE:
+      return PANGO_TEXT_TRANSFORM_NONE;
+    case GTK_CSS_TEXT_TRANSFORM_LOWERCASE:
+      return PANGO_TEXT_TRANSFORM_LOWERCASE;
+    case GTK_CSS_TEXT_TRANSFORM_UPPERCASE:
+      return PANGO_TEXT_TRANSFORM_UPPERCASE;
+    case GTK_CSS_TEXT_TRANSFORM_CAPITALIZE:
+      return PANGO_TEXT_TRANSFORM_CAPITALIZE;
+    default:
+      return PANGO_TEXT_TRANSFORM_NONE;
+    }
+}
+
 static PangoOverline
 get_pango_overline_from_style (GtkTextDecorationStyle style)
 {
@@ -445,6 +465,7 @@ gtk_css_style_get_pango_attributes (GtkCssStyle *style)
   GtkCssFontVariantEastAsian east_asian;
   GString *s;
   char *settings;
+  GtkTextTransform transform;
 
   /* text-decoration */
   decoration_line = _gtk_css_text_decoration_line_value_get (style->font_variant->text_decoration_line);
@@ -655,6 +676,11 @@ gtk_css_style_get_pango_attributes (GtkCssStyle *style)
       g_string_free (s, TRUE);
     }
 
+  transform = _gtk_css_text_transform_value_get (style->font_variant->text_transform);
+
+  if (transform != GTK_CSS_TEXT_TRANSFORM_NONE)
+    attrs = add_pango_attr (attrs, pango_attr_text_transform_new (get_pango_text_transform_from_style (transform)));
+
   return attrs;
 }
 
index 5a78d3d962806e2137ed6b728bca6ffeccf320b8..da878606f0099151d0f48998962f79909f103215 100644 (file)
@@ -159,6 +159,7 @@ struct _GtkCssFontVariantValues {
   GtkCssValue *text_decoration_line;
   GtkCssValue *text_decoration_color; // NULL if currentColor
   GtkCssValue *text_decoration_style;
+  GtkCssValue *text_transform;
   GtkCssValue *font_kerning;
   GtkCssValue *font_variant_ligatures;
   GtkCssValue *font_variant_position;
index a98573c69f252b1a93de0edfd916f08c31a8ecf2..4ee8a200ef86f058e9f7ae8e692d6b5e358ff0d2 100644 (file)
@@ -366,6 +366,18 @@ parse_text_decoration_style (GtkCssStyleProperty *property,
   return value;
 }
 
+static GtkCssValue *
+parse_text_transform (GtkCssStyleProperty *property,
+                      GtkCssParser        *parser)
+{
+  GtkCssValue *value = _gtk_css_text_transform_value_try_parse (parser);
+
+  if (value == NULL)
+    gtk_css_parser_error_syntax (parser, "unknown text transform value");
+
+  return value;
+}
+
 static GtkCssValue *
 parse_font_kerning (GtkCssStyleProperty *property,
                     GtkCssParser        *parser)
@@ -917,6 +929,12 @@ _gtk_css_style_property_init_properties (void)
                                           GTK_CSS_AFFECTS_TEXT_ATTRS,
                                           parse_text_decoration_style,
                                           _gtk_css_text_decoration_style_value_new (GTK_CSS_TEXT_DECORATION_STYLE_SOLID));
+  gtk_css_style_property_register        ("text-transform",
+                                          GTK_CSS_PROPERTY_TEXT_TRANSFORM,
+                                          0,
+                                          GTK_CSS_AFFECTS_TEXT_ATTRS | GTK_CSS_AFFECTS_TEXT_SIZE,
+                                          parse_text_transform,
+                                          _gtk_css_text_transform_value_new (GTK_CSS_TEXT_TRANSFORM_NONE));
   gtk_css_style_property_register        ("font-kerning",
                                           GTK_CSS_PROPERTY_FONT_KERNING,
                                           0,
index 1a2320a6bbd8cc943aff018c33bffb1f4d66c454..8fc0c39c3371928a58e5ccf9975f071810200f05 100644 (file)
@@ -198,6 +198,7 @@ enum { /*< skip >*/
   GTK_CSS_PROPERTY_TEXT_DECORATION_LINE,
   GTK_CSS_PROPERTY_TEXT_DECORATION_COLOR,
   GTK_CSS_PROPERTY_TEXT_DECORATION_STYLE,
+  GTK_CSS_PROPERTY_TEXT_TRANSFORM,
   GTK_CSS_PROPERTY_FONT_KERNING,
   GTK_CSS_PROPERTY_FONT_VARIANT_LIGATURES,
   GTK_CSS_PROPERTY_FONT_VARIANT_POSITION,
@@ -338,6 +339,13 @@ typedef enum /*< skip >*/ {
   GTK_CSS_TEXT_DECORATION_STYLE_WAVY
 } GtkTextDecorationStyle;
 
+typedef enum /*< skip >*/ {
+  GTK_CSS_TEXT_TRANSFORM_NONE,
+  GTK_CSS_TEXT_TRANSFORM_LOWERCASE,
+  GTK_CSS_TEXT_TRANSFORM_UPPERCASE,
+  GTK_CSS_TEXT_TRANSFORM_CAPITALIZE,
+} GtkTextTransform;
+
 /* for the order in arrays */
 typedef enum /*< skip >*/ {
   GTK_CSS_TOP,